# coding=utf-8
# -*- coding: UTF-8 -*-
#
# This file is part of the kernelstudio package.
#
# (c) 2014-2025 zlin <admin@kernelstudio.com>
#
# For the full copyright and license information, please view the LICENSE file
# that was distributed with this source code.
import io
import logging
import typing as t

import docx
from docx.oxml.table import CT_Tbl
from docx.oxml.text.paragraph import CT_P
from docx.table import Table
from docx.text.paragraph import Paragraph

from ksai.document.context import DocumentSection
from ksai.document.converter.attachment import convert_attachment
from ksai.document.extractor.extractor import DocumentExtractorException, AbstractDocumentExtractor
from ksai.document.utils.word import table_to_markdown
from ksai.persistence.storage.attachment import Attachment

logger = logging.getLogger(__name__)


class DocxDocumentExtractor(AbstractDocumentExtractor):

    def __init__(self):
        super().__init__()

    def do_extract(self, attachment: Attachment) -> t.List[DocumentSection]:
        try:
            doc_file = io.BytesIO(convert_attachment(attachment, 'docx'))
            doc = docx.Document(doc_file)
            text = []
            content_items: list[tuple[int, str, Table | Paragraph]] = []

            it = iter(doc.element.body)
            part = next(it, None)
            i = 0
            while part is not None:
                if isinstance(part, CT_P):
                    content_items.append((i, "paragraph", Paragraph(part, doc)))
                elif isinstance(part, CT_Tbl):
                    content_items.append((i, "table", Table(part, doc)))
                i = i + 1
                part = next(it, None)

            # Process sorted content
            for _, item_type, item in content_items:
                if item_type == "paragraph":
                    if isinstance(item, Table):
                        continue
                    text.append(item.text)
                elif item_type == "table":
                    if not isinstance(item, Table):
                        continue
                    try:
                        has_content = False
                        for row in item.rows:
                            if any(cell.text.strip() for cell in row.cells):
                                has_content = True
                                break

                        if has_content:
                            text.append(table_to_markdown(item))
                    except Exception as e:
                        logger.warning(f"Failed extract docx table from DOC: {e}")
                        continue

            return [DocumentSection(
                text="\n".join(text),
            )]
        except Exception as e:
            raise DocumentExtractorException(f"Extract docx file error: {e}") from e

    def extensions(self) -> t.List[str]:
        return ["doc", "docx"]

    def mimes(self) -> t.List[str]:
        return ["application/msword", "application/vnd.openxmlformats-officedocument.wordprocessingml.document"]
